/**
  ETFAna project, Anyang Normal University && IMP-CAS
  \class ETFVMEUnpacker
  \brief unpacker for raw data collected by VME daq
  NOTE that this is devised to be an abstract base class, since VME decoding
  implementation depends on the plugins, thus should be specially written for
  different VME plugin configurations. It is the user's responsibility to derive
  this class to implement for their own experiments.
  \author SUN Yazhou, asia.rabbit@163.com
  \since 2021-09-27
  \date 2021-10-02 last modified
  \attention
  changelog
  <table>
  <tr>  <th>Date         <th>Author      <th>Description                   </tr>
  <tr>  <td>2021-09-27   <td>Asia Sun    <td>file created                  </tr>
  <tr>  <td>2021-10-01   <td>Asia Sun    <td>completing                    </tr>
  </table>

  \copyright Copyright (c) 2021-2024 Anyang Normal U. && IMP-CAS with LGPLv3 LICENSE
*/

#ifndef ETFVMEUnpacker_h
#define ETFVMEUnpacker_h

#include <map>
#include <string>
#include "ETFUnpacker.h"
#include "vme_block_head.h"

class ETFVMEEvent;
class ETFVMERawEvent;

using std::map;
using std::string;

class ETFVMEUnpacker : public ETFUnpacker{
public:
  ETFVMEUnpacker(int id = 0);
  virtual ~ETFVMEUnpacker();

  virtual void Init() override; ///< register the raw data item array
  virtual void Reset() override; ///< clear the output before each event loop

  virtual int GetOneEvent(FILE *file) override; ///< get 1 event to memory from file
  virtual int GetOneEvent(int *fstream) override; ///< get 1 event to memory from stream
  virtual bool UnpackGood() const override{ return true; }

  /// write one event to dst - simulate daq to test online applications in ETFAna
  virtual void WriteOneEvent() override;
  virtual bool Unpack() override; ///< complete the unpacking to clones arrays
  virtual ETFVMEEvent *GetCurrentEvent() const{ return fEvent; }

  int GetBlockIndex() const{ return fBlockHead.index; }
  virtual void PrintSummary() override; ///< print unpacking summary
  void SetDisplayComment(bool opt){ fDisplayComment = opt; }
  int GetNofProcessedBlock(){ return fBlockCnt; }
  virtual void Print() override; ///< Print the unpacked data of the current event

  static const int kBLKSIZE = 8192; ///< the lenght of a block in word (4bytes)
  /// vme card types - DO NOT change the values below
  static const int kV830 = 0, kV785 = 1, kV1190 = 2, kV1290A = 3, kV792N = 4,
    kV965 = 5;

  // ClassDefOverride(ETFVMEUnpacker, 1); // unpacker for VME raw data

protected:
  virtual void Register() override; ///< register raw data to the output tree
  /// customizable user event-decoding for a certain vme-config
  /// user to implement this method should be aware that the data to be decoded
  /// starts from fData[fPos+3] to fData[fPos+fEvent.fEventHead.event_length]
  virtual void UserDecode();
  virtual void UpdateStatus(int ch); ///< update unpack status fUpkSta

  vme_block_head fBlockHead;
  ETFVMEEvent *fEvent;
  ETFVMERawEvent *fRawEvent;

  int fData[kBLKSIZE]; //! ///< to store 1 block
  int fPos; ///< current position in the block
  int fIndex0; ///< the index of the first event, to make the indices starting from 0
  /// note that a block is fixed length (8192 bytes), may contain more than 1 event
  int fBlockCnt; ///< number of blocks processed

  bool fDisplayComment; ///< whether to display the comment
  int fCommentStatus; ///< 0: starting comment; 1: in the middle; 2: ending comment

  static const int NMAXSLOT = 22, NMAXTYPE = 20;
  int fSlots[NMAXSLOT]; ///< <slot => cardtype>
  int fChMap[NMAXSLOT]; ///< <slot => chId0>
  int fCardId[NMAXSLOT]; ///< <slot => cid> for numbering card of the same type
  int fCardCnt[NMAXTYPE]; ///< <cardtype => n> nof cards of the same type
  // map<int, int> fSlots; ///< <slot, cardtype>
  // map<int, int> fChMap; ///< <slot, chId0>
  // map<int, int> fCardId; ///< <slot, id> for numbering card of the same type
  // map<int, int> fCardCnt; ///< <cardtype, n> nof cards of the same type
  struct vme_unpack_status_t{
    int card; ///< -1: init
    int pos; ///< -1: init; 0: GL_H, 1: GL_T; 2: GR_H, 3: GR_T; 4: DATA
    int slot; ///< -1: init;
    int chid0; ///< -1: init;
    void initialize(){
      card = -1; pos = -1;
      slot = -1; chid0 = -1;
    } // end member function initialize
  } fUpkSta; ///< unpack status
  bool fXDebug; ///< for developers
};

#endif
